//////////////////////////////////////////////
// Image.js
//
//////////////////////////////////////////////

/// Class ------------------------------------
	
nkImagesTests.Image = class Image extends nkDebug.TestClass
{
	static instance = new Image ("nkImagesTests.Image") ;

	// Utils
	getImageConstructor (managed)
	{
		return managed ? nkImages.Image : nkImages.unmanaged.Image ;
	}

	createBasicImage (managed)
	{
		// Prepare a descriptor
		const mips = [new nkImages.MipDescriptor (2, 2, 1, 6, 12, 12), new nkImages.MipDescriptor (1, 1, 1, 3, 3, 3)] ;
		const mipOffsets = [0, 12] ;
		let descriptors = [new nkImages.ImageDescriptor (mips, mipOffsets)] ;

		if (!managed)
			descriptors = new nkMemory.unmanaged.BufferCast_nkImages_ImageDescriptor (descriptors) ;
		
		// Prepare the buffer
		const buffer = new nkMemory.Buffer (new Uint8Array ([123, 123, 123, 0, 0, 0, 255, 255, 255, 200, 200, 200, 150, 150, 150])) ;

		// Find constructor
		const ctor = Image.instance.getImageConstructor(managed) ;
		const image = new ctor (buffer, descriptors, nkImages.PIXEL_FORMAT.R8G8B8, 3, false, false) ;

		if (!managed)
			descriptors.delete() ;

		return {mips: mips, mipOffsets: mipOffsets, image: image, buffer: buffer} ;
	}

	// Common test methods
	// Constructor
	testDefaultConstructor (managed)
	{
		const ctor = Image.instance.getImageConstructor(managed) ;
		const image = new ctor () ;

		nkDebug.TestUtils.check(nk.isUnmanagedInstance(image) == !managed, "Managed state unexpected") ;
		nkDebug.TestUtils.check(!image.isView(), "Image not marked as properly holding data") ;
		nkDebug.TestUtils.check(image.getDataBuffer().empty(), "Data not empty") ;
		nkDebug.TestUtils.check(image.getWidth() == 0, "Wrong width") ;
		nkDebug.TestUtils.check(image.getHeight() == 0, "Wrong height") ;
		nkDebug.TestUtils.check(image.getDepthOrArraySize() == 0, "Wrong depth or array size") ;
		nkDebug.TestUtils.check(image.getMipCount() == 0, "Wrong mip count") ;
		nkDebug.TestUtils.check(image.getPixelByteSize() == 0, "Wrong pixel byte size") ;
		nkDebug.TestUtils.check(image.getRowByteSize() == 0, "Wrong row byte size") ;
		nkDebug.TestUtils.check(image.getSliceByteSize() == 0, "Wrong slice byte size") ;

		if (!managed)
			image.delete() ;
	}

	testExplicitDescriptorConstructor (managed)
	{
		const imageInfo = Image.instance.createBasicImage(managed) ;
		const image = imageInfo.image ;
		const buffer = imageInfo.buffer ;
		const mips = imageInfo.mips ;
		const mipOffsets = imageInfo.mipOffsets ;

		nkDebug.TestUtils.check(nk.isUnmanagedInstance(image) == !managed, "Managed state unexpected") ;
		nkDebug.TestUtils.check(!image.isView(), "Image not marked as properly holding data") ;
		nkDebug.TestUtils.check(image.getDataBuffer().getSize() == buffer.getSize(), "Data not right size") ;
		nkDebug.TestUtils.check(image.getMipCount() == 2, "Wrong mip count") ;
		nkDebug.TestUtils.check(image.getPixelByteSize() == 3, "Wrong pixel byte size") ;

		for (let i = 0 ; i < 2 ; ++i)
		{
			const referenceMip = mips[i] ;
			nkDebug.TestUtils.check(image.getWidth(i) == referenceMip._width, "Wrong width " + i) ;
			nkDebug.TestUtils.check(image.getHeight(i) == referenceMip._height, "Wrong height " + i) ;
			nkDebug.TestUtils.check(image.getDepthOrArraySize(i) == referenceMip._depth, "Wrong depth or array size " + i) ;
			
			nkDebug.TestUtils.check(image.getRowByteSize(i) == referenceMip._rowByteSize, "Wrong row byte size " + i) ;
			nkDebug.TestUtils.check(image.getSliceByteSize(i) == referenceMip._sliceByteSize, "Wrong slice byte size " + i) ;
		}

		if (!managed)
			image.delete() ;
	}

	testCopyConstructor (managed0, managed1)
	{
		const imageInfo = Image.instance.createBasicImage(managed0) ;
		const image0 = imageInfo.image ;
		const ctor1 = Image.instance.getImageConstructor(managed1) ;
		const image1 = new ctor1 (image0) ;

		nkDebug.TestUtils.check(nk.isUnmanagedInstance(image0) == !managed0, "Managed state 0 unexpected") ;
		nkDebug.TestUtils.check(nk.isUnmanagedInstance(image1) == !managed1, "Managed state 1 unexpected") ;
		nkDebug.TestUtils.check(!image0.isView(), "Image 0 not marked as properly holding data") ;
		nkDebug.TestUtils.check(!image1.isView(), "Image 1 not marked as properly holding data") ;
		nkDebug.TestUtils.check(image0.getDataBuffer().getSize() == image1.getDataBuffer().getSize(), "Data size not aligned") ;
		nkDebug.TestUtils.check(image0.getMipCount() == image1.getMipCount(), "Wrong mip count") ;
		nkDebug.TestUtils.check(image0.getPixelByteSize() == image1.getPixelByteSize(), "Wrong pixel byte size") ;

		for (let i = 0 ; i < 2 ; ++i)
		{
			nkDebug.TestUtils.check(image0.getWidth(i) == image1.getWidth(i), "Wrong width " + i) ;
			nkDebug.TestUtils.check(image0.getHeight(i) == image1.getHeight(i), "Wrong height " + i) ;
			nkDebug.TestUtils.check(image0.getDepthOrArraySize(i) == image1.getDepthOrArraySize(i), "Wrong depth or array size " + i) ;
			
			nkDebug.TestUtils.check(image0.getRowByteSize(i) == image1.getRowByteSize(i), "Wrong row byte size " + i) ;
			nkDebug.TestUtils.check(image0.getSliceByteSize(i) == image1.getSliceByteSize(i), "Wrong slice byte size " + i) ;
		}

		if (!managed0)
			image0.delete() ;

		if (!managed1)
			image1.delete() ;
	}

	testPixelGet (managed, managedMethodCall)
	{
		// Retrieve image
		const imageInfo = Image.instance.createBasicImage(managed) ;
		const image = imageInfo.image ;
		const buffer = imageInfo.buffer ;
		const mips = imageInfo.mips ;

		// Prepare for pixel retrieval
		const getPixel = function (x, y, z, mip) {return managedMethodCall ? image.getPixel(x, y, z, mip) : image.getPixel_u(x, y, z, mip) ;} ;
		const formatCoordinates = function (x, y, z, mip) {return x + ", " + y + ", " + z + " | " + mip} ;

		const checks =
		[
			// Mip 0
			{x: 0, y: 0, z: 0, mip: 0, color: new nkMaths.Vector (buffer.get(0), buffer.get(1), buffer.get(2), 255)},
			{x: 1, y: 0, z: 0, mip: 0, color: new nkMaths.Vector (buffer.get(3), buffer.get(4), buffer.get(5), 255)},
			{x: 0, y: 1, z: 0, mip: 0, color: new nkMaths.Vector (buffer.get(6), buffer.get(7), buffer.get(8), 255)},
			{x: 1, y: 1, z: 0, mip: 0, color: new nkMaths.Vector (buffer.get(9), buffer.get(10), buffer.get(11), 255)},
			// Mip 1
			{x: 0, y: 0, z: 0, mip: 1, color: new nkMaths.Vector (buffer.get(12), buffer.get(13), buffer.get(14), 255)}
		] ;

		for (const c of checks)
		{
			const pixel = getPixel(c.x, c.y, c.z, c.mip) ;
			nkDebug.TestUtils.check(nk.isUnmanagedInstance(pixel) == !managedMethodCall, "Pixel not in expected managed state") ;
			nkDebug.TestUtils.check(pixel._x == c.color._x, "Wrong pixel R " + formatCoordinates(c.x, c.y, c.z, c.mip)) ;
			nkDebug.TestUtils.check(pixel._y == c.color._y, "Wrong pixel G " + formatCoordinates(c.x, c.y, c.z, c.mip)) ;
			nkDebug.TestUtils.check(pixel._z == c.color._z, "Wrong pixel B " + formatCoordinates(c.x, c.y, c.z, c.mip)) ;
			nkDebug.TestUtils.check(pixel._w == c.color._w, "Wrong pixel A " + formatCoordinates(c.x, c.y, c.z, c.mip)) ;
		}
	}

	nkTests =
	{
		// Constructors
		DefaultConstructorUnmanaged : function () {Image.instance.testDefaultConstructor(false) ;},
		DefaultConstructorManaged : function () {Image.instance.testDefaultConstructor(true) ;},
		ExplicitDescriptorConstructorUnmanaged : function () {Image.instance.testExplicitDescriptorConstructor(false) ;},
		ExplicitDescriptorConstructorManaged : function () {Image.instance.testExplicitDescriptorConstructor(true) ;},
		CopyConstructorUnmanagedUnmanaged : function () {Image.instance.testCopyConstructor(false, false) ;},
		CopyConstructorUnmanagedManaged : function () {Image.instance.testCopyConstructor(false, true) ;},
		CopyConstructorManagedunmanaged : function () {Image.instance.testCopyConstructor(true, false) ;},
		CopyConstructorManagedManaged : function () {Image.instance.testCopyConstructor(true, true) ;},

		// Utils
		PixelGetUnmanagedUnmanaged : function () {Image.instance.testPixelGet(false, false) ;},
		PixelGetUnmanagedManaged : function () {Image.instance.testPixelGet(false, true) ;},
		PixelGetManagedUnmanaged : function () {Image.instance.testPixelGet(true, false) ;},
		PixelGetManagedManaged : function () {Image.instance.testPixelGet(true, true) ;},
	}
}